/*
@Usage:在图片未下载完成前获取图像的图片,支持jpg,gif,png格式。因为有些图像信息格式并不完全
符合标准,因此不保证所有图片都能正确获取结果。如果问题请通知我，谢谢。
*/
package utils
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.ByteArray;
	import flash.utils.Endian;

	/**
	 * 通过二进制流取得图片的尺寸
	 * @author Administrator
	 *
	 */
	public class ImageParser extends EventDispatcher
	{
		/*HexTag 数据标记，每串标记作为标记数组里的一个元素
		leapLength 跳过的字节数
		fileType 文件类型
		parseComplete 解析完成标记
		contentHeight,contentWidth 目标高度和宽度
		isAPPnExist 标记JPG图片的APPn数据段是否存在,默认为无
		*/
		protected static const JPGHexTag:Array=[[0xFF, 0xC0, 0x00, 0x11, 0x08]];
		protected static const PNGHexTag:Array=[[0x49, 0x48, 0x44, 0x52]];
		protected static const GIFHexTag:Array=[[0x21, 0xF9, 0x04], [0x00, 0x2C]];

		protected var APPnTag:Array;
		protected var HexTag:Array;
		protected var address:uint;
		protected var fileType:String;
		protected var byte:uint;
		protected var index:uint=0;
		protected var leapLength:uint;
		private var parseComplete:Boolean=false;
		private var match:Boolean=false;
		private var isAPPnExist:Boolean=false;
		public var contentHeight:uint;
		public var contentWidth:uint;
		public static const PARSE_FAILED:String="PARSE_FAILED";
		public static const PARSE_COMPLETE:String="PARSE_COMPLETE";

		private var bmpBytes:ByteArray;

		public function ImageParser()
		{
		}

		/**
		 * 解析图片尺寸
		 * @param url    图片的源URL（或传入png,jpg,gif）
		 * @param byte   图片的二进制流
		 */
		public function parse(url:String, byte:ByteArray):void
		{
			//验证参数
			if (url == "" || url == null || byte == null || byte.bytesAvailable <= 0)
			{
				return;
			}
			//分析类型
			this.bmpBytes=byte;
			try
			{
				url=url.split("?")[0];
				fileType=url.slice(url.lastIndexOf(".") + 1).toLowerCase();
				switch (fileType)
				{
					case "png":
						HexTag=PNGHexTag;
						break;
					case "jpg":
						HexTag=JPGHexTag;
						APPnTag=new Array();
						break;
					case "gif":
						//gif图像数据endian是LITTLE_ENDIAN
						bmpBytes.endian=Endian.LITTLE_ENDIAN;
						HexTag=GIFHexTag;
						leapLength=4;
						break;
				}
				//立即解析尺寸
				parseHandler();
			}
			catch (error:Error)
			{
				//分析类型出错！！
			}
		}

		//解析数据流
		protected function parseHandler():void
		{
			if (fileType == "jpg")
			{
				JPGAPPnMatch();
			}
			else
			{
				matchHexTag();
			}
			if (parseComplete)
			{
				dispatchEvent(new Event(PARSE_COMPLETE));
			}
		}

		//解析完成
		protected function completeHandler(evt:Event):void
		{
			if (!contentWidth || !contentHeight)
			{
				dispatchEvent(new Event(PARSE_FAILED));
			}
		}

		//比较SOF0数据标签,其中包含width和height信息
		protected function matchHexTag():void
		{
			var len:uint=HexTag.length;
			while (bmpBytes.bytesAvailable > HexTag[0].length)
			{
				match=false;
				byte=bmpBytes.readUnsignedByte();
				address++;
				if (byte == HexTag[0][index])
				{
					//trace(byte.toString(16).toUpperCase());
					match=true;
					if (index >= HexTag[0].length - 1 && len == 1)
					{
						getWidthAndHeight();
						parseComplete=true;
						break;
					}
					else if (index >= HexTag[0].length - 1 && len > 1)
					{
						HexTag.shift();
						index=0;
						matchHexTag();
						break;
					}
				}
				if (match)
				{
					index++;
				}
				else
				{
					index=0;
				}
			}
		}

		//因为JPG图像比较复杂，有的有缩略图APPn标签里(缩略图同样有SOF0标签)，所有先查找APPn标签
		protected function JPGAPPnMatch():void
		{
			while (bmpBytes.bytesAvailable > leapLength)
			{
				match=false;
				byte=bmpBytes.readUnsignedByte();
				address++;
				if (byte == 0xFF)
				{
					byte=bmpBytes.readUnsignedByte();
					address++;
					/*如果byte在0xE1与0xEF之间，即找到一个APPn标签
					APPn标签为(0xFF 0xE1到0xFF 0xEF)
					*/
					if (byte >= 225 && byte <= 239)
					{
						isAPPnExist=true;
						//trace(byte.toString(16).toUpperCase());
						leapLength=bmpBytes.readUnsignedShort() - 2;
						leapBytes(leapLength);
						JPGAPPnMatch();
					}
				}
				//APPn标签搜索完毕后即可开始比较SOF0标签
				if (byte != 0xFF && leapLength != 0)
				{
					matchHexTag();
					break;
				}
				/*如果超过一定数据还未找到APPn,则认为此JPG无APPn,直接开始开始比较SOF0标签。
				这里我取巧选了一个100作为判断,故并不能保证100%有效,但如重新解析的话效率并不好。
				如果谁有更有效的解决办法请告诉我，谢谢。
				*/
				if (address > 100 && isAPPnExist == false)
				{
					matchHexTag();
					break;
				}
			}
		}

		//跳过count个字节数
		protected function leapBytes(count:uint):void
		{
			for (var i:uint=0; i < count; i++)
			{
				bmpBytes.readByte();
			}
			address+=count;
		}

		//获取加载对象的width和height
		protected function getWidthAndHeight():void
		{
			if (fileType == "gif")
			{
				leapBytes(leapLength);
			}
			switch (fileType)
			{
				case "png":
					contentWidth=bmpBytes.readUnsignedInt();
					contentHeight=bmpBytes.readUnsignedInt();
					break;
				case "gif":
					contentWidth=bmpBytes.readUnsignedShort();
					contentHeight=bmpBytes.readUnsignedShort();
					break;
				case "jpg":
					contentHeight=bmpBytes.readUnsignedShort();
					contentWidth=bmpBytes.readUnsignedShort();
					break;
			}
		}
	}
}
